(def movies {:lisa {:lady 2.5 :snakes 3.5 :luck 3.0 :superman 3.5 :you 2.5 :night 3.0} 
            :gene {:lady 3.0 :snakes 3.5 :luck 1.5 :superman 5.0 :night 3.0 :you 3.5} 
            :michael {:lady 2.5 :snakes 3.0 :superman 3.5 :night 4.0 } 
            :claudia{ :snakes 3.5 :luck 3.0 :night 4.5 :superman 4.0 :you 2.5} 
            :mick {:lady 3.0 :snakes 4.0 :luck 2.0 :superman 3.0 :night 3.0 :you 2} 
            :jack { :lady 3.0 :snakes 4.0 :night 3.0 :superman 5.0 :you 3.5} 
            :toby {:snakes 4.5 :you 1.0 :superman 4.0}})
            
(defn similarity "euclidian distance between two users" [my-ref map person1 person2]
  (doseq [item (get-in map [person1])]
    (dosync (alter my-ref + (if-not (nil? (get-in map [person2 (item 0)])) 
      (Math/pow(-(item 1)  (get-in map [person2 (item 0)])    )2 ) 0 ) )))
      (let[result (/ 1 (+ 1 (deref my-ref))) ]result  ))
      
(similarity (ref 0) movies :lisa :toby)
0.2222222222222222

(defn allsimilarities "simmilarity score for all users"[ref-map person map]
	    (doseq [item map](when-not(= person (item 0))
		       (dosync 
			    (alter ref-map assoc (item 0) 
			      (similarity (ref 0) map person (item 0))))))
		   (let [result (deref ref-map)]result ))
         
(allsimilarities (ref {}) :toby movies)
{:jack 0.11764705882352941, :mick 0.3076923076923077, :claudia 0.23529411764705882, :michael 0.2857142857142857, :gene 0.10810810810810811, :lisa 0.2222222222222222}

(defn score "average of other user rankings for one movie" [my-total my-simsum movies person movie] 
	    (doseq [item (allsimilarities(ref {}) person movies)]
		   (if-not (nil?(get-in movies [(item 0) movie]))
			   (dosync 
	       (alter my-total + (* (item 1)(get-in movies [(item 0) movie])))                (alter my-simsum +(item 1))) 0) )
	    (let [result (/(deref my-total) (deref my-simsum))] result))

(defn allmovies "all distinct movies seen by users" [movies-ref movies]
	(doseq [item movies] (doseq [item2 (item 1)] 
	      (dosync (alter movies-ref conj (item2 0)))))
	(let [result (set (deref movies-ref))] result))

(allmovies (ref []) movies)
#{:superman :night :luck :snakes :you :lady}

(defn allscores "ranking movies person havent see" [scores-ref person movies]
	    (doseq [item (allmovies (ref []) movies)] 
		   (when-not(contains? (get-in movies [person]) item)
		     (dosync (alter scores-ref 
		      assoc item (score (ref 0) (ref 0) movies person item))) ))
	    (let [result (deref scores-ref)] result))
       
(allscores (ref {}) :toby movies)
{:lady 2.7561242939959363, :luck 2.461988486074373, :night 3.5002478401415877}

 
(let [mapa (allsimilarities (ref {}) :toby movies) ] 
 (into (sorted-map-by 
  (fn [key1 key2] (compare (mapa  key2) (mapa  key1)))) 
mapa))
{:mick 0.3076923076923077, :michael 0.2857142857142857, :claudia 0.23529411764705882, :lisa 0.2222222222222222, :jack 0.11764705882352941, :gene 0.10810810810810811}


(defn sort-map-by-value "higher values go first"[mapa] 
  (let [oldmap  mapa] (into (sorted-map-by 
    (fn [key1 key2] (compare (oldmap key2) (oldmap key1)))) oldmap)))

(sort-map-by-value (allscores (ref {}) :toby movies))
{:night 3.5002478401415877, :lady 2.7561242939959363, :luck 2.461988486074373}
